﻿#pragma once
#include <iostream>
#include <openssl/evp.h>
#include <openssl/ec.h>
#include <sstream>
#include <iomanip>
#include <string>

#include <string.h>

#include <stdio.h>

#include <openssl/ec.h>

#include <openssl/ecdsa.h>

#include <openssl/objects.h>

#include <openssl/err.h>

#include <stdio.h>
#include <openssl/bio.h>
#include <openssl/rand.h>
#include <openssl/txt_db.h>
#include <openssl/evp.h>

#include <openssl/md2.h>
#include <openssl/md4.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/mdc2.h>
#include <openssl/bn.h>
#include <openssl/ripemd.h>
#include <openssl/md2.h>
class TestEcdh {
public:
	static void handleErrors() {
		std::cout << "============handleErrors===================" << std::endl;
	}
//	static EVP_PKEY* get_peerkey(EVP_PKEY* pkey1) {
//		EVP_PKEY* pkey = 0;
//		EVP_PKEY_CTX* pctx, * kctx;
//		/* Create the context for parameter generation */
//		if (NULL == (pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL))) handleErrors();
//
//		/* Initialise the parameter generation */
//		if (1 != EVP_PKEY_paramgen_init(pctx)) handleErrors();
//
//		/* We're going to use the ANSI X9.62 Prime 256v1 curve */
//		if (1 != EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1)) handleErrors();
//
//		/* Create the parameter object params */
//		if (!EVP_PKEY_paramgen(pctx, &pkey)) handleErrors();
//
//		/* Create the context for the key generation */
//		if (NULL == (kctx = EVP_PKEY_CTX_new(pkey, NULL))) handleErrors();
//
//
//		EVP_PKEY_CTX_free(pctx);
//
//
//		return pkey;
//	}
//	//https://wiki.openssl.org/index.php/Elliptic_Curve_Diffie_Hellman
//	static void testECDH() {
//
//		size_t slen = 128;
//
//		size_t* secret_len =&slen;
//
//		std::cout << "============Ecdh===================" << std::endl;
//		EVP_PKEY_CTX* pctx, * kctx;
//		EVP_PKEY_CTX* ctx;
//		unsigned char* secret;//共享密钥
//		EVP_PKEY* pkey = NULL, * peerkey, * params = NULL;
//		/* NB: assumes pkey, peerkey have been already set up */
//		//假定peerke已经生成
//
//		/* Create the context for parameter generation */
//		//创建参数上下文（自己）
//
//		if (NULL == (pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL))) handleErrors();
//
//		/* Initialise the parameter generation */
//		//初始化上下文参数（自己）
//
//		if (1 != EVP_PKEY_paramgen_init(pctx)) handleErrors();
//
//		/* We're going to use the ANSI X9.62 Prime 256v1 curve */
//		//我们将使用 ANSI X9.62 Prime 256v1 曲线
//
//		if (1 != EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1)) handleErrors();
//
//		/* Create the parameter object params */
//		//
//		if (!EVP_PKEY_paramgen(pctx, &params)) handleErrors();
//
//		/* Create the context for the key generation */
//		//创建密钥生成的上下文（自己）
//
//		if (NULL == (kctx = EVP_PKEY_CTX_new(params, NULL))) handleErrors();
//
//		/* Generate the key */
//		//生成密钥（自己）
//
//		if (1 != EVP_PKEY_keygen_init(kctx)) handleErrors();
//		if (1 != EVP_PKEY_keygen(kctx, &pkey)) handleErrors();
//
//		char privateKeyRaw[32] = { 0 };
//		size_t privateLen = 0;
//		if (1 != EVP_PKEY_get_raw_private_key(pkey, (unsigned char*)privateKeyRaw, &privateLen))
//		{
//			std::cout << "err, len is " << privateLen << std::endl;
//		}
//
//		/* Get the peer's public key, and provide the peer with our public key -
//		 * how this is done will be specific to your circumstances */
//		 //获取交换方公钥(模拟)
//
//		peerkey = get_peerkey(pkey);
//
//		/* Create the context for the shared secret derivation */
//		//创建 【共享密钥上下文】用自己的密钥建立关系
//
//		if (NULL == (ctx = EVP_PKEY_CTX_new(pkey, NULL))) handleErrors();
//
//		/* Initialise */
//		//初始化【共享密钥上下文】
//		if (1 != EVP_PKEY_derive_init(ctx)) handleErrors();
//
//		/* Provide the peer public key */
//		//绑定交换方的密钥到【共享密钥上下文】
//		if (1 != EVP_PKEY_derive_set_peer(ctx, peerkey)) handleErrors();
//
//		/* Determine buffer length for shared secret */
//		//设置共享密钥的长度
//
//		if (1 != EVP_PKEY_derive(ctx, NULL, secret_len)) handleErrors();
//
//		/* Create the buffer */
//		//设置共享密钥的缓存区(空间)
//		if (NULL == (secret = (unsigned char*)OPENSSL_malloc(*secret_len))) handleErrors();
//
//		/* Derive the shared secret */
//		//生成共享密钥
//
//		if (1 != (EVP_PKEY_derive(ctx, secret, secret_len))) handleErrors();
//
//		std::string ssecrtestr((char*)secret);
//
//		//fprintf(stdout, "%02X", v);
//
//		
//
//		auto hexSecret = hexStrByBytes(secret, *secret_len);
//
//		std::cout << "hexSecret:::" << hexSecret << std::endl;
//
//		EVP_PKEY_CTX_free(ctx);
//		EVP_PKEY_free(peerkey);
//		EVP_PKEY_free(pkey);
//		EVP_PKEY_CTX_free(kctx);
//		EVP_PKEY_free(params);
//		EVP_PKEY_CTX_free(pctx);
//
//		/* Never use a derived secret directly. Typically it is passed
//		 * through some hash function to produce a key */
//	}
	//字节转hex
	static std::string hexStrByBytes(const uint8_t* data, size_t len)
	{
		std::stringstream ss;//默认输出十进制
		ss << std::hex;//校正为16进制

		for (int i(0); i < len; ++i) {
			//函数用于设置字段的宽度
			//setw() 函数只对紧接着的输出产生作用
			//setfill函数应仅用作流操纵器。
			ss << std::setw(2) << std::setfill('0') << (int)data[i];
		}

		return ss.str();
	}
//#include <openssl/evp.h>
//#include <openssl/rsa.h>
//	static void generatorKey() {
//
//
//		EVP_PKEY_CTX* ctx;
//		EVP_PKEY* pkey = NULL;
//
//		ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
//		if (!ctx)
//		{
//			handleErrors();
//			return;
//		}
//		/* Error occurred */
//		if (EVP_PKEY_keygen_init(ctx) <= 0) {
//			handleErrors();
//			return;
//		}
//		/* Error */
//		if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048) <= 0)
//			/* Error */
//		{
//			handleErrors();
//			return;
//		}
//		/* Generate key */
//		if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
//			handleErrors();
//
//		}
//		/* Error */
//		EVP_PKEY_CTX_free(ctx);
//		EVP_PKEY_free(pkey);
//		std::cout << "====================generatorKey success==========================" << std::endl;
//	}
//	static void generatorKeyByParams() {
//		EVP_PKEY_CTX* ctx;
//		ENGINE* eng;
//		EVP_PKEY* pkey = NULL, * param;
//
//		/* Assumed param, eng are set up already */
//		ctx = EVP_PKEY_CTX_new(param, eng);
//		if (!ctx) {
//			handleErrors();
//			return;
//		}
//		/* Error occurred */
//		if (EVP_PKEY_keygen_init(ctx) <= 0) {
//			handleErrors();
//			return;
//		}
//		/* Error */
//
//	/* Generate key */
//		if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
//			handleErrors();
//			return;
//		}
//		/* Error */
//	}

	/*
	* 基础知识：
	* 
	////DH密钥交换的整个过程概括如下:
	(1)Alice和Bob交换掩盖了他们各自私钥的公钥
	(2)双方均使用对方的公钥和己方的私钥计算出共享密钥
	(3)敌手通过观察公钥不能获得私钥的任何信息，更不能计算出共享密钥

	实际上，DH密钥交换是非常不安全的。你能花上几秒找出其不安全的原因吗？这是因为Alice接收任何来自Bob的公钥，
	所以我可以拦截Bob发向Alice的公钥，并用我的公钥替换掉Bob的公钥，这样我就可以冒充Bob（反之，我也可以向Bob冒充Alice）。
	这样的中间人(Man-in-the-Middle，MITM)攻击者方法可以成功地攻击该密钥交换协议。那么如何修复协议的这个漏洞呢?
	用另一个加密原语增强这个密钥交换协议，或者提前知道Bob的公钥。但这不就意味着我们又回到了原点，即如何在协议开始之前确定双方公钥

	*/

	//生成两对ECC密钥，并用它做签名和验签，并生成共享密钥。
	static int testECCECDH() {
		EC_KEY* key1, * key2;

		EC_POINT* pubkey1, * pubkey2;

		EC_GROUP* group1, * group2;

		int  ret, nid, size, i, sig_len;

		unsigned char* signature, digest[20];

		BIO* berr;

		EC_builtin_curve* curves;

		int crv_len;

		char  shareKey1[128], shareKey2[128];

		int  len1, len2;
		/* 构造EC_KEY数据结构 */

		key1 = EC_KEY_new();

		if (key1 == NULL)
		{
			printf("EC_KEY_new err!\n");
			return -1;
		}

		key2 = EC_KEY_new();

		if (key2 == NULL)
		{

			printf("EC_KEY_new err!\n");

			return -1;

		}

		/* 获取实现的椭圆曲线个数 */

		crv_len = EC_get_builtin_curves(NULL, 0);

		curves = (EC_builtin_curve*)malloc(sizeof(EC_builtin_curve) * crv_len);

		/* 获取椭圆曲线列表 */

		EC_get_builtin_curves(curves, crv_len);
		/*

	  nid=curves[0].nid;会有错误，原因是密钥太短

	  */

	  /* 选取一种椭圆曲线 */

		nid = curves[25].nid;

		/* 根据选择的椭圆曲线生成密钥参数group */

		group1 = EC_GROUP_new_by_curve_name(nid);

		if (group1 == NULL)
		{

			printf("EC_GROUP_new_by_curve_name err!\n");

			return -1;

		}

		group2 = EC_GROUP_new_by_curve_name(nid);

		if (group1 == NULL)
		{

			printf("EC_GROUP_new_by_curve_name err!\n");

			return -1;

		}
		/* 设置密钥参数 */

		ret = EC_KEY_set_group(key1, group1);

		if (ret != 1)
		{

			printf("EC_KEY_set_group err.\n");

			return -1;

		}

		ret = EC_KEY_set_group(key2, group2);

		if (ret != 1)
		{

			printf("EC_KEY_set_group err.\n");

			return -1;

		}
		/* 生成密钥 */

		ret = EC_KEY_generate_key(key1);
		
		

		if (ret != 1)
		{

			printf("EC_KEY_generate_key err.\n");

			return -1;

		}

		ret = EC_KEY_generate_key(key2);

		if (ret != 1)
		{

			printf("EC_KEY_generate_key err.\n");

			return -1;

		}
		/* 检查密钥 */

		ret = EC_KEY_check_key(key1);

		if (ret != 1)
		{

			printf("check key err.\n");

			return -1;

		}

		/* 获取密钥大小 */

		size = ECDSA_size(key1);

		printf("size %d \n", size);

		for (i = 0; i < 20; i++)
			memset(&digest[i], i + 1, 1);

		signature =(unsigned char*) malloc(size);

		ERR_load_crypto_strings();

		berr = BIO_new(BIO_s_file());

		BIO_set_fp(berr, stdout, BIO_NOCLOSE);
		/* 签名数据，本例未做摘要，可将digest中的数据看作是sha1摘要结果 */

		ret = ECDSA_sign(0, digest, 20, signature, (unsigned int*) & sig_len, key1);

		if (ret != 1)
		{

			ERR_print_errors(berr);

			printf("sign err!\n");

			return -1;

		}

		/* 验证签名 */

		ret = ECDSA_verify(0, digest, 20, signature, sig_len, key1);

		if (ret != 1)
		{

			ERR_print_errors(berr);

			printf("ECDSA_verify err!\n");

			return -1;

		}
		/* 获取对方公钥，不能直接引用 */

		pubkey2 =(EC_POINT*) EC_KEY_get0_public_key(key2);

		/* 生成一方的共享密钥 */

		//自己的私钥+对方公钥计算出共享密钥
		len1 = ECDH_compute_key(shareKey1, 128, pubkey2, key1, NULL);

		pubkey1 = (EC_POINT*)EC_KEY_get0_public_key(key1);


		
		/// ///////////////////////////////////////////
		//private key to hex str
		privateKeyToHexStr(key1);
		privateKeyToHexStr(key2);

		/*const BIGNUM * bigNumPrivateKey=EC_KEY_get0_private_key(key1);
		char* privateKey1Hex= BN_bn2hex(bigNumPrivateKey);

		std::cout << "pubkey1Hex:" << string(privateKey1Hex) << std::endl;*/
		//public key to hex str
		publicKeyToHexStr(key1, group1);
		publicKeyToHexStr(key2, group2);

		/*BN_CTX* bnctx = NULL;
		bnctx = BN_CTX_new();

		char* pkk = EC_POINT_point2hex(group1, pubkey1, POINT_CONVERSION_COMPRESSED, bnctx);

		std::cout << "pubkey1Hex:" << string(pkk) << std::endl;*/
		//

		/* 生成另一方共享密钥 */
		//自己的私钥+对方公钥计算出共享密钥
		len2 = ECDH_compute_key(shareKey2, 128, pubkey1, key2, NULL);

		if (len1 != len2)
		{
			printf("err\n");
		}

		else
		{
			std::string shareKey1Hex = hexStrByBytes((const uint8_t*)&shareKey1, len1);
			std::string shareKey2Hex = hexStrByBytes((const uint8_t*)&shareKey2, len1);

			std::cout <<"shareKey1Hex:" << shareKey1Hex << std::endl;
			std::cout <<"shareKey2Hex:" << shareKey2Hex << std::endl;

			ret = memcmp(shareKey1, shareKey2, len1);

			auto ss = hexStrByBytes((const uint8_t*)&shareKey2, sizeof(shareKey2));
			if (ret == 0)
				printf("生成共享密钥成功: \n");

			else
				printf("生成共享密钥失败\n");

		}
		printf("test ok!\n");

		BIO_free(berr);

		EC_KEY_free(key1);

		EC_KEY_free(key2);

		free(signature);

		free(curves);

		return 0;
	}
	/// <summary>
	/// 公钥转换为hex
	/// </summary>
	/// <param name="key1"></param>
	/// <param name="group1"></param>
	/// <returns></returns>
	static std::string publicKeyToHexStr(EC_KEY* key1, EC_GROUP* group1) {
		//EC_GROUP* group1 = NULL;
		EC_POINT* pubkey1 = (EC_POINT*)EC_KEY_get0_public_key(key1);
		BN_CTX* bnctx = NULL;
		bnctx = BN_CTX_new();

		char* pkk = EC_POINT_point2hex(group1, pubkey1, POINT_CONVERSION_COMPRESSED, bnctx);

		std::cout << "pubkey1Hex:" << std::string(pkk) << std::endl;
		return std::string(pkk);
	}
	/// <summary>
	/// 私钥转换为hex
	/// </summary>
	/// <param name="key1"></param>
	/// <returns></returns>
	static std::string privateKeyToHexStr(EC_KEY* key1) {
		const BIGNUM* bigNumPrivateKey = EC_KEY_get0_private_key(key1);
		char* privateKey1Hex = BN_bn2hex(bigNumPrivateKey);

		std::cout << "pubkey1Hex:" << std::string(privateKey1Hex) << std::endl;
		return std::string(privateKey1Hex);
	}
	/// <summary>
	/// BIO加密
	/// </summary>
	static void testBIOCrypt() {
		/* 加密 */
		BIO* bc = NULL, * b = NULL;
		const EVP_CIPHER* c = EVP_des_ecb();
		int len, i;
		char tmp[1024];
		unsigned char key[8], iv[8];
		for (i = 0; i < 8; i++)
		{
			memset(&key[i], i + 1, 1);
			memset(&iv[i], i + 1, 1);
		}
		bc = BIO_new(BIO_f_cipher());
		BIO_set_cipher(bc, c, key, iv, 1);
		b = BIO_new(BIO_s_null());
		b = BIO_push(bc, b);
		std::string dataTxt = "openssl";

		std::cout << "原始数据::" << dataTxt << std::endl;
		len = BIO_write(b, dataTxt.c_str(), 7);
		len = BIO_read(b, tmp, 1024);

		std::cout << "加密后的数据:" << std::string(tmp, len) << std::endl;
		BIO_free(b);

		//解密
		testBIODecrypt(tmp, key, iv,len);
	}
	/// <summary>
	/// BIO解密
	/// </summary>
	/// <param name="tmp"></param>
	/// <param name="key"></param>
	/// <param name="iv"></param>
	/// <param name="len"></param>
	static void testBIODecrypt(char tmp[1024],unsigned char key[8],unsigned char iv[8],int len) {
		/* 解密 */
		BIO* bdec = NULL, * bd = NULL;
		const EVP_CIPHER* cd = EVP_des_ecb();
		bdec = BIO_new(BIO_f_cipher());
		BIO_set_cipher(bdec, cd, key, iv, 0);
		bd = BIO_new(BIO_s_null());
		bd = BIO_push(bdec, bd);
		len = BIO_write(bdec, tmp, len);
		len = BIO_read(bdec, tmp, 1024);
		std::cout <<"解密数据:" << std::string(tmp,len) << std::endl;
		BIO_free(bdec);
	}


	/// <summary>
	/// 生成随机数,并写入文件
	/// </summary>
	static void testRand() {
		char buf[4172];
		const char *p;
		unsigned char out[4172], filename[50];
		int ret, len;
		BIO* print;
		//RAND_screen();//todo 
		//RAND_screen/RAND_event
		//Windows 特有函数，用来计算内部随机数，他们调用了RAND_seed

		//随机数种子
		std::string seeds = "fc8627ba57542d514b443332332d35304d2d522d3139303530313032000000000000000057542d514b443332332d35304d2d542d31393035303130320000000000000000026168620000100029916c7ac803e187cd7c1f4134517407b24ff90c8534e360a3f8d1d5c2cb0565b787aa71ca6a131a88261182a6b9bbb1c4749bfe7af469b8fa79cb3f9a339d3805e1a3dc07b43a76eb83cca20233ffdae6cb84615ac6b437a1d1a66ada6e322560f951c6c8567ead2db0230fca0963ca26f492c7a93fb98b0bf77dad908c3abd1cc0b277d35f7affcb02973556fbf99513159ea4b0e2d34912dd9c8ca334e1943002715b5dffae0b6e4f23e607bfa635198c598c2ff046234949f142fc8b9b8223e7ce1b90eff61142a004c5cf959d0fb23ede764bf15e10cc34c44800376329bd83ca4d4cb0b55fb254444b571cd9b4262a0209e84a50734aec02bb636179b398de61700ef90e09cac783334d44b9aa5dedadb102be13ed0e7d27deee15265eb92527c5320fb0b11388a2f759d0dc82a324e248217750dcacb9b86a11c10258f31c61201363b36ca332f640d271157cbfc4dc8bf02b0fca123d67b917128873582751acb5ebef69fb36adc23a179faa9d3b134a43db8d332f38b05152c357aadc80075f1e36669f307770edc4d9fd661a360baae75600840a0e738ddcaefba121ca839d922316d1c834fe3cf88a985da14e7a158f03a64e8291dba1ba8e43b954d3e3dfee92ff454bed8808f2f95b6befda6e3ee74757764da09001ce33dcba0da20ae319f0a886582730c842992ddc09accf97043a49edec39829d2ce7a307ce9aed5f79f19d0d11af0fda6a2a62a393679659aca78e2347bd407957d7a386e4cd3cb7bdca3b89cd4ce3daeea154a4420b71fa5586de2238c3d1d16cd5be74be29a9f0b6bb66d9ecfa6d8498efbcb44706c3b1518837d86c6eb438ac3d6d9afece0d86465614f051dbed34830c4a021c89a3ece486f8b8fc47d79824e738ec35a632123b471d976af7825aab3adb8f158c83bebf4cd5934c7be85a5b989006413616e1676638eeb2277a8c2b47b6a0257ae8bc971e565637086e3a23871f8a0ff31747ce7cd8b8b56cb382d29cc3465e3463ad0a740871e6e25d982fb92d346eff5a212debe3e758180e755264c22d4ba2805980f4a004963faa75791d5a5b554768cf7e93abd9daf8a6b92f5d07bd9dfc0cb2d1845011d647323c6dae8ca7c0080d8a6369f01d1b3c24a9420c413db0526afe5dc312c2acc68c9949f916530682e08a903061219f09ede792120424aa19543c2dc80db83d70c89a80cac71446d22335404ac0a82014d0e56b2e9433c9dab1ee6da85fff12bdc55a8da9134824db6e575777672a66c36e92f5af9008391a0f07efee2fbf2374e8786259eb36073d8cad040255c0547744498616454f347357d52d43fde75c3f7e0720c22a68c97e4a62bc0dcb7ecf441625c173108e061cc507c0b16c633653239d9fa259e5b1fb5f58ce3d61e2f1f733e20fb98133db14a0dea78d54bbbbbabed7c0b47fb68213f029e7f4863108bb910c971bd79ee90955dce8bfd093a09bfe0d0c31b954aea90c40521a4fbf71f99cc620d085b3c5f2b9b4579896a9374e566da892dac38aa57eaae9d66fb1e33dbd27b2975eb0a7a67bf3980937e2678757f8ea11de43494d7d36de13fe11c15eb9dad394437ad8323b33c3b081d1c5bcaed4a301cd70035c35eb9a77c1b14a797cc7e24f9ebbca146bf242de7a68baf42c6a32111e9c4375f3841bca94526ae68de27323556bf28a03d1435b2cb64e633cf2cd4b5755759ea79712bfc12194f47320978e3e0cd502854808e08410fa45162e64d2b8af2eb0b52d433905562f4b63eb8db5fae96101f75e95f2f8e1f018658f3c5d16435c2f0cd47ea9eedea89ca8886d84689851574f38265f530e8b772cbbc8215cfe8428ff2ae5c3bc370f8b39d26329b86b1a4a4a652b17d3d888b33c90eb7c382f2252ebba8bdf574ee1109ef0affa1b4481398b2743a82b16f0f99400ce20a20704171149c62cdf1d23be3e3b46c56042d2f0022f7a975378a9be5dd32a723b1000b72191ccca6d8af09420eeb94e584b3b33b1d48a66cd581fae4ae0451d4163e4eae31ed38aeb723a27f061d636657992d73fb8132e8f65980928bb3093bc5374779861ae0fec585aca4b18624aa0fc2bd34996ff976ad5aab31af94a2094526d2daa73446924cf6e1de00b507dbd7d5e0a3c7902838e52190bf085b537810053578c6fb69e9b51aac73aee5f0906247504bb476847cc845fa88e56577e8d83d526cb891c1f181dedb886f900eab15baf55a170bb118a56d90a6be66832d9b490b1dc4e76dbb59c7c8e3d9755aa2f9c80455a83790b77984857393d940fb05c1e9f9cd6e5926d577ea27e3dee35fc0682727979e99789638ac9b05667ae185a590a39d30d5f19d408d1b3fa8688d81b177c1e91ce989b0fac6a7ede0eb4bba17af4c950ad9f4bce052103f103474c7e43cc476e6d7fba74020d78da420ffbee9c5b38030b7c7a193c905d6c38d520396fcfa5d98f5e10c8e6047b9f4b12fd3f8f5c33b53951eff59e27d65834f9f30e788c620976a81488926d66c7628676e9c5904fb8ed5198d189c61fca383067b9ba883c8df3cb3f54cd4b6cb3da39623d3151d76070b886a76772f8795d1a04fe96475c92db6869b902c1f21dda88f0c4beec381c1e16b19eef59f870cfc350f695a5621598358a9b7af25c7272a8bcc59d74d02a20423188032a06887366326119d2fd4b2e67550f0dc49a1ac56e88cf76e1be1c92c97fd8a45624af75bdd709552324f73ddda7c6eb0dfda91a650da004fe98d7a6ef6aa7843976fcbc3c5fc040fa195c2801bd953743f55b3c7bc5f7d684f2dafb081c26fcc022de652ae115b9d53fa017543abe27dd4921d7fe980fbb9c65f57f082de51200d2bcdfa4d27252a952accd6aaa32a6c0d6f283a4cb16454ec2632f8cd7884502906ce2457e424696f2eef8fa57a84e4ab3f0d8ad0788751014d9c3b0aa097647ba5f018dec58cb40f07c183d8d461a8b542690504471a64c23ffa670362d67b6223bce4665fd971542c0d6a6810a27aea976a2d5d0997e6d900e296a5b8a987e4c105622e37d9f5d1fbb03d1e9388a125e47270ff8b94c1d96211201eb6349c1140b8ab18c912dec530a7452d793d95666fdd47e09ec2c3c7e9060a9d06666ad14a1ec99905093a45972d13f0a0a38a47618cb624deac7a546f4af928d858bfabb1f1d0fb2b8c9dc13264d50b20d6f3da37a5269c3c883d13bef7e8809ec0a8ba3002ed58b2943351c3164791547684866b1dc89ac619dd3e5173ec7d731cacd2fce54ed9d658644d8a5a6108a18aa45cc63c219b859d80a8ac39cb3cffe35f84136e94cf45cf94db6e289c39048a872d6c84a6758190dab2a845a1c24de26bb3741e24662381945efa6565f00a35c872c37c0cf4ce2360c0f333eb01e3869ce4906417050d6a3c2164f012fda0d2e77fcac0631b62e374481d19ee8afbcce032a486c2b4faf851da81f5f666c8fa10c3927811eca8ce28d47698b7d2e50078aff141bfa41c0ed2d2cd02104bbf401b112d9adf64cce15299da3c5a92f7ffdc690a7f44b9b031875353240b05ccf4894dbb54b166d43ef0d632d3ac28f789d0f6fc22f0d0418b396920bd8a4e4050eade572655d715b70c77aebe9177f555bee12be182b759f2fb5765881b32ff4eed108ccc20358df2a4dd81e9be270b9e4d2c2f38945e583fcc05d4a647710a926ad23957c836fc8085e35390ae045c11411c01d948cc545bfe4ba77c39b201e35873e7b5dadecb16175bdf00d99341d0f734c5decc9da826c6213ec7a6dc90e21aeb51e359f5b478c4645987e5cb25fa8c3d0a8ded551a9d592e52a473cf2b5bee97da3bd455ebdd3b899b3c45bad165e0ee99b3263366d9fab910e24e434090cf718c554bfdb2772ac2f1c0ecf905147c26e0140a0dab3e074b0dbf93e319d6784fa945b259622b7a040fcc7da25b1a42b90e0566430a1ebd29271bdb55c64b6cdf36baec0010608e0abc58c007fa8854d1691b68b3b465732ba91956275e972e0e132687de6d9c7b99aad6433df9b9e043238498d8e04a714e7d972e3c777fc448d955fc8be4c8ede7c2f37952c330576e034abd04c513254c4f55625d432cbfe307d5b97ac2c243b804978204dc8ba59c99df9ebe20cf43e8c126549a727e38cd980b1764709e05aa81e1e37864c99a9776e4dd9a3a3549100557a5bf1ac3ff5055306629c305461052dbc9421de8699c13bd598c4e8a7cd8e018078879d4fad2349a246ff922638967266f2b72e37d324c25bf87d4d86a723d68113206ae25b9d84cd8d3f1de15f4f81f860ca87713e4a2453e51c58a2ef2d0b3f4decfbfe1a0dc44fe4fa9aae4d1fb4c8c00b9884b9358592a3400d55be13acf484404b78b2aa6aa8db02c17d1b5585955328633ed2162a99bd7d7ca2b1382cbf07a0a46e13bf6bc1902ca5c80d581dcd62a2df5c42c167b3425a44c23b295b7dfe804a6d91ed09a880c3100a589387fad4bf656b23d347d5c58e7bae9533ab2a58a6df8ffd6447c97361d1f4d29e7dcb59145860f5b76f4e20bb87d6150974627d6272e0ba05d09013e1322c911c1cfdbaa0892d8b410d5f8d44bdf71afc74897134a78f3fcae7739ae166dee3ee734d9fc9bb8911561dfd25f4097f8ac2bd7d577d6ce84f9247b028063d57bd2952ec62654c898123703b02ecc6ebe47eb1300f33596a1888462a1facc2b2a0637a75b1d4c3bb9413de1acccf8809b9c778aed73e300e9951a4a0d3f9681a06c589ea10bcd70a5aa307f61177d0fcdde66548f3aa208d3f57e6010c7d24216dd26ff2788ffc0f877814a5a92f645302619d063c5505b24b8b266367fcbb4457ba497f401887eee7156fd6fbbf9cf81c954b4631177c693a185748515713bf085d0fb09a9ec5d87952180096f22d5b11059ad42d8f21ec7b5ef66b107580400e64c015487abff3d35c7770125fe7105d873d84b38cccdc9a66969aab138ce73d6beaed5fbfa7a5935425967ffdd97650eef01311b94a58e7bad92c9c38a3fff5ae72e204669cbcce194da89d7461ed5c743d784283a4aa29df02f743005fa439f139cd8c477dcbe668e2be133228c5cfa553201b00c86a85582f113d39acdc499f1fe94e5799373624a984a23648ac92426100c4c6a684e388c9a12aaf487b373bf939ad59aef19bcc798db9da8c7a476e2ef5770ef966f118df687e1fd85e186a7e025f5c133632027c43505ecbe8212181fc1883e4ab71848d0256b160bc96e11db9e00db3dd8e73a495c75f7ebe8c1f58acc73e1a60a984805d8695702d061f32d0d88e2aca67be2a35c9d6b9a051bff1dc4d55f425a5da2c923992a90b36659f30185c22cf48ede4f04d71be69ecfcd5751871f5ec4fe7f60a2842fda05231eae56708340d1a618b61c3ed331913b4a16c28f07b568b65eb2fc0989f11d9fc6f122334f21d9cfa16795e270f2e8e5f5e9f9b8eade5ff7f54df2c03b3053dca47d3d2f612ae08be6e6ab217d2245bc0f869ab2bd2dd2a8d30403d817f37aa3ddfde70561ecb7f453c459b3a4f7bf64eb0347ceebd6178fa60b5ec15749b629690baafd880844b8ad05375add48a5cef03479a129e73a42fd0899019eaa64d9474e83d1c2e32484057862af636e8ec60e091b59cc9ac6e94c38cc6ffb719d503d8a1191587e8a6d24741444a893c0fb20038fc0345ec991b43b6eebec3c4059a68e796d833722d91bd1d656997b58001b644d6e9f899b503a0f1fd35633299bd316f3588b1921d4937c89521d33b2251bf2f5f17dd3acab31ece2226a1";
		std::vector<char> bytes;
		//16进制转二进制
		for (unsigned int i = 0; i < seeds.length(); i += 2) {
			std::string byteString = seeds.substr(i, 2);
			char byte = (char)strtol(byteString.c_str(), NULL, 16);
			bytes.push_back(byte);
		}
		std::string s(bytes.begin(), bytes.end());
		int sSize = s.length();

		//strcpy(buf, seeds.c_str());//长度溢出(seeds=8344>buf=4172)会报错：Stack around the variable 'buf' was corrupted.
		strcpy(buf, s.c_str());

		int rand_len = 4172;
		//来计算内部随机数
		RAND_add(buf, rand_len, strlen(buf));
		strcpy(buf, "a2842fda05231eae56708340d1a618b61c3ed331913b4a16c28f07b568b65eb2fc09");//
		RAND_seed(buf, rand_len);
		while (1)
		{
			ret = RAND_status();
			if (ret == 1)
			{
				printf("seeded enough!\n");
				break;
			}
			else
			{
				printf("not enough sedded!\n");
				RAND_poll();
			}
		}
		
		//C:\Users\126李\.rnd

		p = RAND_file_name((char*)filename, 50);
		std::string ss = std::string(p);
		if (p == NULL)
		{
			printf("can not get rand file\n");
			return;
		}
		ret = RAND_write_file(p);
		len = RAND_load_file(p, 1024);
		
		ret = RAND_bytes(out, rand_len);
		
		if (ret != 1)
		{
			printf("err.\n");
			return;
		}

		print = BIO_new(BIO_s_file());
		BIO_set_fp(print, stdout, BIO_NOCLOSE);
		BIO_write(print, out, rand_len);
		
		std::string hex = hexStrByBytes(out, rand_len);
		std::cout << "result rand hex:" << hex << std::endl;

		BIO_write(print, "\n", 2);
		BIO_free(print);
		RAND_cleanup();
		
	}
	/*
	typedef struct txt_db_st
	{
	int num_fields;
	STACK *data;
	LHASH **index;
	int (**qual)(char **);
	long error;
	long arg1;
	long arg2;
	char **arg_row;
	} TXT_DB;
	意义如下：
	num_fields：表明文本数据库的列数。
	data：用来存放数据，每一行数据组织成为一个字符串数组(每个数组值对应该行的一
	列)， 并将此数组地址 push 到堆栈中。
	index：哈希表数组，每一列对应一个哈希表。每一列都可以建哈希表，如果不建哈希
	表将不能查找该列数据。
	qual：一个函数地址数组，数组的每个元素对应一列，进行插入该列哈希表前的过滤。
	这些函数用于判断一行数据的一列或者多列是否满足某种条件，如果满足将不能插入到
	哈希表中去(但是能存入堆栈)。每一列都可以设置一个这样的函数。这些函数由用户实
	现。比如，一个文本数据库中，有名字列和年龄列，并且要求名字长度不能小于2，年
	龄不能小于0 和大于200。用户为名字列实现了一个qual 函数，只用来检查名字长度，
	对于年龄列实现一个qual 函数，只用来检查年龄。当用户要插入一条记录，名字长度
	53
	为1，但是年龄合法，那么该记录能插入到年龄列对应的哈希表中，而不能插入名字列
	对应的哈希表。
	error、arg1、arg2 和arg_row 用于存放错误信息。
	
	
	
	*/
	//TXTDB
	static void testTXTDB() {
		TXT_DB* db = NULL;
		BIO *out = NULL;
		BIO* in;
		int num, ret;
		char** added = NULL, ** rrow = 0, ** row = NULL;
		in = BIO_new_file("txtdb.dat", "r");
		num = 1024;
		db = TXT_DB_read(in, 4);
		added = (char**)OPENSSL_malloc(sizeof(char*) * (3 + 1));
		added[0] = (char*)OPENSSL_malloc(10);
#if 1
		strcpy(added[0], "skp");
#else
		strcpy(added[0], "a"); /* 不能插入名字对应的哈希表 */
#endif
		added[1] = (char*)OPENSSL_malloc(10);
		strcpy(added[1], "22");
		added[2] = (char*)OPENSSL_malloc(10);
		strcpy(added[2], "chairman");
		added[3] = NULL;
		ret = TXT_DB_insert(db, added);
		
			if (ret != 1)
			{
				printf("err!\n");
				return;
			}
		ret = TXT_DB_create_index(db, 0, name_filter, (OPENSSL_LH_HASHFUNC)index_name_hash, (OPENSSL_LH_COMPFUNC)index_name_cmp);
		//	ret = TXT_DB_create_index(db, 0, name_filter, (OPENSSL_LH_HASHFUNC)indexNameHash, (OPENSSL_LH_COMPFUNC)indexNameCmp);

		if (ret != 1)
		{
			printf("err\n");
			return;
		}
		row = (char**)malloc(2 * sizeof(char*));
		row[0] = (char*)malloc(10);
		strcpy(row[0], "skp");
		row[1] = NULL;
		rrow = TXT_DB_get_by_index(db, 0, row);
		if (rrow != NULL)
			printf("%s %s %s\n", rrow[0], rrow[1], rrow[2]);
		out = BIO_new_file("txtdb2.dat", "w");
		ret = TXT_DB_write(out, db);
		TXT_DB_free(db);
		BIO_free(in);
		BIO_free(out);
	}
	/* 名字过滤 */
	static int name_filter(char** in)
	{
		if (strlen(in[0]) < 2)
			return 0;
		return 1;
	}
	//static unsigned long indexNameHash(const OPENSSL_STRING* row)
	//{
	//	return OPENSSL_LH_strhash(row[0]);
	//}

	//static int indexNameCmp(const OPENSSL_STRING* rowA, const OPENSSL_STRING* rowB)
	//{
	//	printf("rowA name:[%s] vs rowB name:[%s] \n", rowA[0], rowB[0]);
	//	return strcmp(rowA[0], rowB[0]);
	//}


	//typedef unsigned long (*OPENSSL_LH_HASHFUNC) (const void *);

	static unsigned long index_name_hash(const char** a)
	{
		const char* n;
		n = a[0];
		while (*n == '0') n++;
		return(lh_strhash(n));
	}
	//typedef int (*OPENSSL_LH_COMPFUNC) (const void *, const void *);
	static int index_name_cmp(const char** a, const char** b)
	{
		const char* aa, * bb;
		for (aa = a[0]; *aa == '0'; aa++);
		for (bb = b[0]; *bb == '0'; bb++);
		return(strcmp(aa, bb));
	}

	/*
	大数一般指的是位数很多的数。计算机表示的数的大小是有限的，精度也是有限的，
	它不能支持大数运算。密码学中采用了很多大数计算，为了让计算机实现大数运算，用户需
	要定义自己的大数表示方式并及实现各种大数运算。Openssl 为我们提供了这些功能，主要用于非对称算法
	*/

	static void testBigNum() {
		int ret;
		BIGNUM* a;
		BN_ULONG w;
		a = BN_new();
		BN_one(a);
		w = 2685550010;
		ret = BN_add_word(a, w);//给大数a加上w，如果成功，返回1
		if (ret != 1)
		{
			printf("a+=w err!\n");
			BN_free(a);
			return;
		}
		char *p = BN_bn2hex(a);
		std::cout <<"big num hex:" << std::string(p) << std::endl;
		BN_free(a);
	}
	//BASE64
	//编码是一种常用的将十六进制数据转换为可见字符的编码
	//与ASCII 码相比，它占用的空间较小。BASE64 编码在rfc3548 中定义。
	
	static void testBase64EncodingDecode() {
		EVP_ENCODE_CTX *ectx,*dctx;
		ectx = EVP_ENCODE_CTX_new();
		dctx= EVP_ENCODE_CTX_new();

		unsigned char in[500], out[800], d[800];
		int inl, outl, i, total, ret, total2;
		EVP_EncodeInit(ectx);
		for (i = 0; i < 500; i++)
		{
			std::cout <<"i="<<i<<" ASCII:" << char(i) << std::endl;//http://c.biancheng.net/c/ascii/
			char cc = (char)i;
			memset(&in[i], i, 1);//C 库函数 void *memset(void *str, int c, size_t n) 复制字符 c（一个无符号字符）到参数 str 所指向的字符串的前 n 个字符。
		}
		for (int j = 0; j < sizeof(in);j++) {
			std::cout << "j=" << j << " ASCII:" << in[j] << std::endl;//http://c.biancheng.net/c/ascii/
		}
		inl = 500;
		total = 0;
		//encode
		// 
		//in为编码原始数据
		EVP_EncodeUpdate(ectx, out, &outl, in, inl);
		total += outl;
		EVP_EncodeFinal(ectx, out + total, &outl);
		total += outl;
		printf("%s\n", out);

		//decode
		EVP_DecodeInit(dctx);
		outl = 500;
		total2 = 0;
		//d为解码出的原始数据

		ret = EVP_DecodeUpdate(dctx, d, &outl, out, total);//BASE64 解码
		if (ret < 0)
		{
			printf("EVP_DecodeUpdate err!\n");
			return ;
		}
		//todo ?
		std::string instr = (char*)in;
		std::string outstr = (char*)d;
		if (instr==outstr) {
			printf("in===d!\n");
		}

		total2 += outl;
		ret = EVP_DecodeFinal(dctx, d, &outl);
		total2 += outl;

		EVP_ENCODE_CTX_free(ectx);
		EVP_ENCODE_CTX_free(dctx);
	}

	/**
		摘要函数用于将任意数据通过计算获取唯一对应值
	，而这个值的长度比较短。它是一种
多对一的关系。理论上，这个短的值就对应于原来的数据。这个过程是不可逆的，即不能通
过摘要值来计算原始数据。摘要在信息安全中有非常重要的作用。很多网络应用都通过摘要
计算来存放口令。摘要是安全协议中不可或却的要素，特别是身份认证与签名。用户需要对
数据进行签名时，不可能对大的数据进行运算，这样会严重影响性能。如果只对摘要结果进
行计算，则会提供运算速度。常用摘要算法有：sha、sha1、sha256 以及md5 等。其他还有
md4、md2、mdc2 以及ripemd160
	
	
	*/

	/*
	mdc2、md4 和md5 摘要结果为16 字节，128 比特；
	ripemd160、sha 和sha1 摘要结果为20 字节，160bit；
	sha256摘要结果为32 字节，256bit；
	sha512摘要结果为64 字节，512bit
	*/
	static void testDigest() {
		unsigned char in[] = "3dsferyewyrtetegvbzVEgarhaggavxcv";
		unsigned char out[20];
		size_t n;
		int i;
		n = strlen((const char*)in);
#ifdef OPENSSL_NO_MDC2
		printf("默认openssl 安装配置无MDC2\n");
#else
		MDC2(in, n, out);
		printf("MDC2 digest result :\n");
		for (i = 0; i < 16; i++)
			printf("%x ", out[i]);
#endif
		RIPEMD160(in, n, out);
		printf("RIPEMD160 digest result :\n");
		/*for (i = 0; i < 20; i++)
			printf("%x ", out[i]);
		MD2(in, n, out);
		printf("MD2 digest result :\n");*/
		for (i = 0; i < 16; i++)
			printf("%x ", out[i]);
		MD4(in, n, out);
		printf("\n\nMD4 digest result :\n");
		for (i = 0; i < 16; i++)
			printf("%x ", out[i]);
		MD5(in, n, out);
		printf("\n\nMD5 digest result :\n");
		/*for (i = 0; i < 16; i++)
			printf("%x ", out[i]);
		
		SHA(in, n, out);
		printf("\n\nSHA digest result :\n");*/
		for (i = 0; i < 20; i++)
			printf("%x ", out[i]);
		SHA1(in, n, out);
		printf("\n\nSHA1 digest result :\n");
		for (i = 0; i < 20; i++)
			printf("%x ", out[i]);
		SHA256(in, n, out);
		printf("\n\nSHA256 digest result :\n");
		for (i = 0; i < 32; i++)
			printf("%x ", out[i]);
		SHA512(in, n, out);
		printf("\n\nSHA512 digest result :\n");
		for (i = 0; i < 64; i++)
			printf("%x ", out[i]);
		printf("\n");
	}
	//hmac参见man


};